using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom;
using System.Diagnostics;
using Microsoft.CSharp;
using System.IO;
using System.CodeDom.Compiler;
using OpenComposite.EII.Designer.BRules;
using OpenComposite.Base.Designer;
using System.ComponentModel;

namespace OpenComposite.EII.BRules
{
	public static class BusinessRulesCodeGenerator
	{
		#region Initialization
		#endregion

		#region Public Members

		#region Methods

		public static string GenerateBusinessRuleCode(
			Designer.BRules.BusinessRuleSymbol businessRuleSymbol,
			out List<string> vocabulary,
			out List<string> executeRuleNames)
		{
			CodeMemberMethod method = generateBRuleMethod(businessRuleSymbol,
				out vocabulary, out executeRuleNames);
			return generateCSharp(method);
		}

		public static string GenerateBusinessPolicyCode(
			string businessPolicyName,
			List<Designer.BRules.BusinessRuleSymbol> listBRuleSymbols)
		{
			CodeMemberMethod method = generateBPolicyMethod(businessPolicyName, listBRuleSymbols);
			return generateCSharp(method);
		}
		
		public static string GenerateOrchestrationRuleCode(
			Designer.BRules.BusinessRuleSymbol bruleSymbol,
			out Dictionary<string, string> parameters,
			out List<string> results,
			out List<int> bruleIDs,
			out List<int> ruleConstIDs)
		{
			CodeMemberMethod method = generateWFRuleMethod(bruleSymbol,
														   out parameters,
														   out results,
														   out bruleIDs,
														   out ruleConstIDs);
			return generateCSharp(method);
		}

		#endregion

		#endregion

		#region Private Members

		#region Methods

		private static string generateCSharp(CodeMemberMethod method)
		{
			string code = "";
			try {
				CSharpCodeProvider csharp = new CSharpCodeProvider();
				CodeGeneratorOptions options = new CodeGeneratorOptions();
				options.ElseOnClosing = true;
				options.IndentString = "\t";
				using ( StringWriter sw = new StringWriter() ) {
					csharp.GenerateCodeFromMember(method, sw, options);
					code = sw.ToString();
				}
			} catch ( Exception ex ) {
				string msg = string.Format("Error while generating C#-code.{0}{1}",
					Environment.NewLine, ex.Message);

				//System.Windows.Forms.MessageBox.Show(msg, "Generate C#",
				//    System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
				Debug.WriteLine(msg);

				code = "";
			}
			return code;
		}

		#region Business Rules
		private static CodeMemberMethod generateBRuleMethod(
			OpenComposite.EII.Designer.BRules.BusinessRuleSymbol bruleSymbol,
			out List<string> vocabulary,
			out List<string> executeRuleNames)
		{
			CodeStatementCollection ruleExecutions = null;
			// create method : bool RuleName()
			CodeMemberMethod method = new CodeMemberMethod();
			method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
			method.Name = bruleSymbol.Name;
			method.ReturnType = new CodeTypeReference(typeof(bool));

			// add try - catch to method
			CodeTryCatchFinallyStatement trycatch = new CodeTryCatchFinallyStatement();
			method.Statements.Add(trycatch);

			// add if conditions
			CodeStatementCollection statements = generateIFCodeExpression(bruleSymbol,
				out ruleExecutions, out vocabulary, out executeRuleNames);
			if ( statements != null && statements.Count > 0 ) {
				trycatch.TryStatements.AddRange(statements);
			}

			// add if - else to try
			//CodeConditionStatement ifelse = new CodeConditionStatement();
			//trycatch.TryStatements.Add(ifelse);

			//ifelse.Condition = generateIFCodeExpression(bruleSymbol,
			//    out ruleExecutions, out vocabulary, out executeRuleNames);

			//// insert generated ruleExecution statement before the ifelse CodeConditionStatement
			//if ( ruleExecutions != null ) {
			//    foreach ( CodeStatement statement in ruleExecutions ) {
			//        trycatch.TryStatements.Insert(0, statement);
			//    }
			//}

			//// add setResult("RuleName", "THEN-ResultString") to if part
			//ifelse.TrueStatements.Add(
			//    new CodeMethodInvokeExpression(
			//        null,
			//        "setResult",
			//        new CodePrimitiveExpression(bruleSymbol.Name),
			//        new CodePrimitiveExpression(bruleSymbol.ThenElse.ThenResultString)));

			//// add setResult("RuleName", "ELSE-ResultString") to else part
			//if ( bruleSymbol.ThenElse.ElseResultString.Trim() != "" ) {
			//    ifelse.FalseStatements.Add(
			//        new CodeMethodInvokeExpression(
			//            null,
			//            "setResult",
			//            new CodePrimitiveExpression(bruleSymbol.Name),
			//            new CodePrimitiveExpression(bruleSymbol.ThenElse.ElseResultString)));
			//}

			// add new clause, "trace" and "return false" to catch
			trycatch.CatchClauses.Add(
				new CodeCatchClause(									// catch ( Exception ex ) ...
					"ex",
					new CodeTypeReference(typeof(Exception)),
					new CodeExpressionStatement(
						new CodeMethodInvokeExpression(						// Trace.WriteLine( ...
							new CodeTypeReferenceExpression(typeof(Trace)),
							"WriteLine",
							new CodeMethodInvokeExpression(						// ex.ToString() ...
								new CodeVariableReferenceExpression("ex"),
								"ToString"))),								// ... );
					new CodeMethodReturnStatement(						// return ...
						new CodePrimitiveExpression(false))					// false;
				));

			// add return true to method
			method.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(true)));

			return method;
		}

		private static CodeStatementCollection generateIFCodeExpression(
			BusinessRuleSymbol bruleSymbol,
			out CodeStatementCollection ruleExecutions,
			out List<string> vocabulary,
			out List<string> executeRuleNames)
		{
			CodeStatementCollection statements = new CodeStatementCollection();

			ruleExecutions = new CodeStatementCollection();
			vocabulary = new List<string>();
			executeRuleNames = new List<string>();

			if ( bruleSymbol.IfList.Count > 0 ) {
				foreach ( THENResultSymbol thenSym in bruleSymbol.ThenList ) {
					CodeStatementCollection ruleExec;
					List<string> vocab;
					List<string> ruleNames;
					// generate composite if conditions with AND/OR based on connected symbols
					CodeExpression codeExpr = generateIFCodeExpressionRecursive(thenSym,
						out ruleExec, out vocab, out ruleNames);
					if ( codeExpr != null ) {
						ruleExecutions.AddRange(ruleExec);
						vocabulary.AddRange(vocab);
						executeRuleNames.AddRange(ruleNames);
						CodeConditionStatement condition = new CodeConditionStatement();
						condition.Condition = codeExpr;
						condition.TrueStatements.Add(
							new CodeMethodInvokeExpression(
								null,
								"setResult",
								new CodePrimitiveExpression(bruleSymbol.Name),
								new CodePrimitiveExpression(thenSym.ResultString)));
						condition.TrueStatements.Add(
							new CodeMethodReturnStatement(new CodePrimitiveExpression(true)));
						statements.Add(condition);
					}
				}
			}
			if ( !string.IsNullOrEmpty(bruleSymbol.Else.ResultString) ) {
				statements.Add(new CodeExpressionStatement(
					new CodeMethodInvokeExpression(
						null,
						"setResult",
						new CodePrimitiveExpression(bruleSymbol.Name),
						new CodePrimitiveExpression(bruleSymbol.Else.ResultString))));
			}
			return statements;
		}

		private static CodeExpression generateIFCodeExpressionRecursive(
			DesignerControl current,
			out CodeStatementCollection ruleExecutions,
			out List<string> vocabulary,
			out List<string> executeRuleNames)
		{
			CodeExpression codeExprCurrent = null;
			CodeExpression codeExprLast = null;
			DesignerControl[] predecessors = current.GetPredecessors();

			ruleExecutions = new CodeStatementCollection();
			vocabulary = new List<string>();
			executeRuleNames = new List<string>();

			foreach ( DesignerControl dc in predecessors ) {
				CodeStatementCollection currentRuleExec = null;
				List<string> currentVocab = null;
				List<string> currentRules = null;

				// be sure that codeExprCurrent is null
				codeExprCurrent = null;
				if ( dc is Designer.Generic.ANDSymbol || dc is Designer.Generic.ORSymbol ) {
					// generate CodeExpression for current ANDSymbol or ORSymbol
					codeExprCurrent = generateIFCodeExpressionRecursive(dc,
						out currentRuleExec, out currentVocab, out currentRules);
				} else if ( dc is Designer.BRules.IFSymbol ) {
					// generate the CodeExpress for the current IFSymbol
					codeExprCurrent = generateIFConditionCodeExpression(
						( (Designer.BRules.IFSymbol)dc ).IFCondition,
						out currentRuleExec, out currentVocab, out currentRules);
				}
				if ( currentRuleExec != null ) {
					// add new rule execution statements to ruleExecutions
					ruleExecutions.AddRange(currentRuleExec);
				}
				// if exists add new vocabulary to vocabulary list
				if ( currentVocab != null && currentVocab.Count > 0 )
					vocabulary.AddRange(currentVocab);
				// if exists add new rule names to rule name list
				if ( currentRules != null && currentRules.Count > 0 )
					executeRuleNames.AddRange(currentRules);

				if ( codeExprCurrent != null && codeExprLast != null ) {
					CodeBinaryOperatorExpression binOp = new CodeBinaryOperatorExpression();
					// combine the current and the last CodeExpression
					// based on the type of the current control
					binOp.Left = codeExprLast;
					binOp.Right = codeExprCurrent;
					if ( current is Designer.Generic.ORSymbol )
						binOp.Operator = CodeBinaryOperatorType.BooleanOr;
					else
						binOp.Operator = CodeBinaryOperatorType.BooleanAnd;
					codeExprLast = binOp;
					codeExprCurrent = null;
				} else if ( codeExprCurrent != null && codeExprLast == null ) {
					// if no last CodeExpression exists
					codeExprLast = codeExprCurrent;
					codeExprCurrent = null;
				}
			}
			if ( ruleExecutions.Count == 0 )
				ruleExecutions = null;

			return codeExprLast;
		}

		private static CodeExpression generateIFConditionCodeExpression(
			IFSymbol.Condition condition,
			out CodeStatementCollection ruleExecutions,
			out List<string> vocabulary,
			out List<string> executeRuleNames)
		{
			// initialize vocabulary list and list of executed rule names
			vocabulary = new List<string>();
			executeRuleNames = new List<string>();

			// add used vocabulary to list
			if ( condition.LeftPart == IFSymbol.ConditionPartType.Variable )
				vocabulary.Add(condition.LeftValueString);
			if ( condition.RightPart == IFSymbol.ConditionPartType.Variable )
				vocabulary.Add(condition.RightValueString);

			// add used rule names to list
			if ( condition.LeftPart == IFSymbol.ConditionPartType.Rule )
				executeRuleNames.Add(condition.LeftValueString);
			if ( condition.RightPart == IFSymbol.ConditionPartType.Rule )
				executeRuleNames.Add(condition.RightValueString);

			#region Old Code (with code snippets)
			//// generate left part, right part and operator
			//string partL = generatePart(condition.LeftPart, condition.LeftValueString, condition.RightPart);
			//string partR = generatePart(condition.RightPart, condition.RightValueString, condition.LeftPart);
			//string opFormatString = getCSharpOperatorFormatString(condition.Operator);

			//// combine to code snippet
			//string code = string.Format(opFormatString, partL, partR);

			//// create CodeSnippetExpression
			//CodeSnippetExpression ifcondition = new CodeSnippetExpression(code);
			#endregion

			CodeExpression exprLeft = generatePart(condition.LeftPart, condition.LeftValueString, condition.RightPart);
			CodeExpression exprRight = generatePart(condition.RightPart, condition.RightValueString, condition.LeftPart);

			if ( exprLeft == null || exprRight == null )
				throw new NullReferenceException("Error in generateIFConditionCodeExpression (exprLeft == null || exprRight == null).");
			CodeExpression ifcondition = generateCondition(exprLeft, condition.Operator, exprRight);
			if ( ifcondition == null )
				throw new NullReferenceException("Error in generateIFConditionCodeExpression (ifcondition == null).");

			// create rule executions
			CodeStatement statement = null;
			if ( condition.LeftPart == IFSymbol.ConditionPartType.Rule ||
				 condition.RightPart == IFSymbol.ConditionPartType.Rule ) {
				ruleExecutions = new CodeStatementCollection();
				if ( condition.LeftPart == IFSymbol.ConditionPartType.Rule ) {
					statement = getRuleExecutionStatement(condition.LeftValueString);
					if ( statement != null )
						ruleExecutions.Add(statement);
				}
				if ( condition.RightPart == IFSymbol.ConditionPartType.Rule ) {
					statement = getRuleExecutionStatement(condition.RightValueString);
					if ( statement != null )
						ruleExecutions.Add(statement);
				}
				if ( ruleExecutions.Count == 0 )
					ruleExecutions = null;
			} else {
				ruleExecutions = null;
			}

			return ifcondition;
		}

		private static CodeStatement getRuleExecutionStatement(string ruleName)
		{
			return new CodeConditionStatement(
				new CodeBinaryOperatorExpression(
					new CodeMethodInvokeExpression(null, ruleName),
					CodeBinaryOperatorType.IdentityEquality,
					new CodePrimitiveExpression(false)),
				new CodeMethodReturnStatement(new CodePrimitiveExpression(false)));
		}
		private static CodeExpression generatePart(
			IFSymbol.ConditionPartType conditionPartType,
			string valueString,
			IFSymbol.ConditionPartType otherPartType)
		{
			CodeExpression codeExpr = null;
			if ( conditionPartType == IFSymbol.ConditionPartType.String ||
				 conditionPartType == IFSymbol.ConditionPartType.ResultString ) {
				if ( otherPartType == IFSymbol.ConditionPartType.Number )
					codeExpr = new CodeMethodInvokeExpression(			// double.Parse("valueString")
						new CodeTypeReferenceExpression(typeof(double)),
						"Parse",
						new CodePrimitiveExpression(valueString));
				else
					codeExpr = new CodePrimitiveExpression(valueString);// "valueString"
			} else if ( conditionPartType == IFSymbol.ConditionPartType.Number ) {
				double d;
				if ( double.TryParse(valueString, out d) )
					codeExpr = new CodePrimitiveExpression(d);			// 100000 => valueString as double
				else
					codeExpr = new CodePrimitiveExpression(valueString);// "valueString"
			} else if ( conditionPartType == IFSymbol.ConditionPartType.Boolean ) {
				BooleanConverter bc = new BooleanConverter();
				try {
					codeExpr = new CodePrimitiveExpression(bc.ConvertFromString(valueString));// True => valueString as bool
				} catch {
					codeExpr = new CodePrimitiveExpression(valueString);// "valueString"
				}
			} else if ( conditionPartType == IFSymbol.ConditionPartType.Variable ) {
				if ( otherPartType == IFSymbol.ConditionPartType.Number )
					codeExpr = new CodeMethodInvokeExpression(			// toNumber("valueString")
						null,
						"toNumber",
						new CodePrimitiveExpression(valueString));
				else if ( otherPartType == IFSymbol.ConditionPartType.Boolean )
					codeExpr = new CodeMethodInvokeExpression(			// toBool("valueString")
						null,
						"toBool",
						new CodePrimitiveExpression(valueString));
				else
					codeExpr = new CodeMethodInvokeExpression(			// toString("valueString")
						null,
						"toString",
						new CodePrimitiveExpression(valueString));
			} else if ( conditionPartType == IFSymbol.ConditionPartType.Rule ) {
				if ( otherPartType == IFSymbol.ConditionPartType.Number )
					codeExpr = new CodeMethodInvokeExpression(			// double.Parse(getResult("valueString"))
						new CodeTypeReferenceExpression(typeof(double)),
						"Parse",
						new CodeMethodInvokeExpression(
							null,
							"getResult",
							new CodePrimitiveExpression(valueString)
						)
					);
				else
					codeExpr = new CodeMethodInvokeExpression(			// getResult("valueString")
						null,
						"getResult",
						new CodePrimitiveExpression(valueString));
			} else if ( conditionPartType == IFSymbol.ConditionPartType.RuleConstant ) {
			}
			return codeExpr;
		}
		#region Old Code with code snippets
		//private static string generatePart(
		//    IFSymbol.ConditionPartType conditionPartType,
		//    string valueString,
		//    IFSymbol.ConditionPartType otherPartType)
		//{
		//    string codeExpr = "";
		//    if ( conditionPartType == IFSymbol.ConditionPartType.String ) {
		//        if ( otherPartType == IFSymbol.ConditionPartType.Number )
		//            codeExpr = string.Format("double.Parse(\"{0}\")", valueString);
		//        else
		//            codeExpr = string.Format("\"{0}\"", valueString);
		//    } else if ( conditionPartType == IFSymbol.ConditionPartType.Number ) {
		//        codeExpr = valueString;
		//    } else if ( conditionPartType == IFSymbol.ConditionPartType.Variable ) {
		//        if ( otherPartType == IFSymbol.ConditionPartType.Number )
		//            codeExpr = string.Format("toNumber(\"{0}\")", valueString);
		//        else
		//            codeExpr = string.Format("toString(\"{0}\")", valueString);
		//    } else if ( conditionPartType == IFSymbol.ConditionPartType.Rule ) {
		//        if ( otherPartType == IFSymbol.ConditionPartType.Number )
		//            codeExpr = string.Format("double.Parse(getResult(\"{0}\"))", valueString);
		//        else
		//            codeExpr = string.Format("getResult(\"{0}\")", valueString);
		//    }
		//    return codeExpr;
		//}
		#endregion
		private static CodeExpression generateCondition(
			CodeExpression left, IFSymbol.ConditionOperator op, CodeExpression right)
		{
			CodeExpression codeExpr;

			switch ( op ) {
				case IFSymbol.ConditionOperator.Equals:
					codeExpr = new CodeBinaryOperatorExpression(	// left == right
						left, CodeBinaryOperatorType.IdentityEquality, right);
					break;
				case IFSymbol.ConditionOperator.NotEquals:
					codeExpr = new CodeBinaryOperatorExpression(	// left != right
						left, CodeBinaryOperatorType.IdentityInequality, right);
					break;
				case IFSymbol.ConditionOperator.Greater:
					codeExpr = new CodeBinaryOperatorExpression(	// left > right
						left, CodeBinaryOperatorType.GreaterThan, right);
					break;
				case IFSymbol.ConditionOperator.Less:
					codeExpr = new CodeBinaryOperatorExpression(	// left < right
						left, CodeBinaryOperatorType.LessThan, right);
					break;
				case IFSymbol.ConditionOperator.GreaterEquals:
					codeExpr = new CodeBinaryOperatorExpression(	// left >= right
						left, CodeBinaryOperatorType.GreaterThanOrEqual, right);
					break;
				case IFSymbol.ConditionOperator.LessEquals:
					codeExpr = new CodeBinaryOperatorExpression(	// left <= right
						left, CodeBinaryOperatorType.LessThanOrEqual, right);
					break;
				case IFSymbol.ConditionOperator.Contains:			// left.Contains(right)
					codeExpr = new CodeMethodInvokeExpression(
						left,
						"Contains",
						right);
					break;
				case IFSymbol.ConditionOperator.NotContains:
					codeExpr = new CodeBinaryOperatorExpression(	// left.Contains(right) == false
						new CodeMethodInvokeExpression(
							left,
							"Contains",
							right),
						CodeBinaryOperatorType.IdentityEquality,
						new CodePrimitiveExpression(false));
					break;
				default:
					codeExpr = null;
					break;
			}

			return codeExpr;
		}
		#region Old Code with code snippets
		//private static string getCSharpOperatorFormatString(IFSymbol.ConditionOperator op)
		//{
		//    string str = "";
		//    switch ( op ) {
		//        case IFSymbol.ConditionOperator.Equals:
		//            str = "{0} == {1}";
		//            break;
		//        case IFSymbol.ConditionOperator.NotEquals:
		//            str = "{0} != {1}";
		//            break;
		//        case IFSymbol.ConditionOperator.Greater:
		//            str = "{0} > {1}";
		//            break;
		//        case IFSymbol.ConditionOperator.Less:
		//            str = "{0} < {1}";
		//            break;
		//        case IFSymbol.ConditionOperator.GreaterEquals:
		//            str = "{0} >= {1}";
		//            break;
		//        case IFSymbol.ConditionOperator.LessEquals:
		//            str = "{0} <= {1}";
		//            break;
		//        case IFSymbol.ConditionOperator.Contains:
		//            str = "{0}.Contains({1})";
		//            break;
		//        case IFSymbol.ConditionOperator.NotContains:
		//            str = "!( {0}.Contains({1}) )";
		//            break;
		//    }
		//    return string.Format("({0})", str);
		//}
		#endregion

		#endregion

		#region Business Policy

		private static CodeMemberMethod generateBPolicyMethod(string name,
			List<Designer.BRules.BusinessRuleSymbol> listBRuleSymbols)
		{
			// Preconditions
			if ( name == null || name == "" )
				throw new Exception("Invalid Business Policy name.");
			if ( listBRuleSymbols == null || listBRuleSymbols.Count == 0 )
				throw new Exception("Business Policy doesn't contain Business Rules.");

			// Variable Decalration
			CodeMemberMethod method;
			List<string> ruleNames = new List<string>();
			List<string> resultStrings = new List<string>();

			// create business policy method: public List<string> BPolicyName()
			method = new CodeMemberMethod();
			method.Name = name;
			method.ReturnType = new CodeTypeReference(typeof(List<string>));

			// add boolean variable for rules success return value: bool ok = true;
			method.Statements.Add(
				new CodeVariableDeclarationStatement(
					typeof(bool),
					"ok",
					new CodePrimitiveExpression(true)
				)
			);
			// add list variable for business rule result strings: List<string> listResults = new List<string>();
			method.Statements.Add(
				new CodeVariableDeclarationStatement(
					typeof(List<string>),
					"listResults",
					new CodeObjectCreateExpression(typeof(List<string>))
				)
			);

			// add calls of business rules
			foreach ( Designer.BRules.BusinessRuleSymbol brule in listBRuleSymbols ) {
				Repository.RepositoryBusinessRule rule = brule.RepositoryItem as Repository.RepositoryBusinessRule;
				if ( rule != null ) {
					// add current rule: ok = ok && RuleName();
					method.Statements.Add(
						new CodeAssignStatement(
							new CodeVariableReferenceExpression("ok"),						// ok =
							new CodeBinaryOperatorExpression(								// ok && RuleName()
								new CodeVariableReferenceExpression("ok"),
								CodeBinaryOperatorType.BooleanAnd,
								new CodeMethodInvokeExpression(null, rule.BusinessRuleName)
							)
						)
					);
					ruleNames.Add(rule.BusinessRuleName);
				}
			}

			// add check rule returns: if ( ok == false )
			method.Statements.Add(
				new CodeConditionStatement(							// if
					new CodeBinaryOperatorExpression(				// ok == false
						new CodeVariableReferenceExpression("ok"),
						CodeBinaryOperatorType.IdentityEquality,
						new CodePrimitiveExpression(false)),
					new CodeMethodReturnStatement(					// return null;
						new CodePrimitiveExpression(null))
				)
			);

			// add business rule result strings to list: list.Add(getResult("RuleName"));
			foreach ( string rulenm in ruleNames ) {
				method.Statements.Add(
					new CodeMethodInvokeExpression(
						new CodeVariableReferenceExpression("list"),
						"Add",
						new CodeMethodInvokeExpression(
							null,
							"getResult",
							new CodePrimitiveExpression(rulenm)
						)
					)
				);
			}

			// add return result string list: return list;
			method.Statements.Add(
				new CodeMethodReturnStatement(
					new CodeVariableReferenceExpression("list")
				)
			);

			// return generated CodeMemberMethod
			return method;
		}

		#endregion

		#region Business Rule for Orchestration
		private static CodeMemberMethod generateWFRuleMethod(BusinessRuleSymbol bruleSymbol,
			out Dictionary<string, string> parameters, out List<string> results, out List<int> bruleIDs,
			out List<int> ruleConstIDs)
		{
			List<string> vocabulary;
			List<string> executeRuleNames;
			CodeStatementCollection ruleExecutions = null;
			parameters = new Dictionary<string, string>();
			results = new List<string>();
			bruleIDs = new List<int>();
			ruleConstIDs = new List<int>();
			//_conditionIndex = 0;
			// create method : string RuleName(type Var1, type Var2, ...)
			CodeMemberMethod method = new CodeMemberMethod();
			method.Attributes = MemberAttributes.Public | MemberAttributes.Final | MemberAttributes.Static;
			method.Name = bruleSymbol.Name;
			method.ReturnType = new CodeTypeReference(typeof(string));

			// add try - catch to method
			CodeTryCatchFinallyStatement trycatch = new CodeTryCatchFinallyStatement();
			method.Statements.Add(trycatch);

			// generate statements
			CodeStatementCollection statements = generateIFCodeExpressionWF(bruleSymbol,
			    out ruleExecutions, out vocabulary, out executeRuleNames,
			    ref parameters, ref bruleIDs, ref ruleConstIDs);

			//// add if - else to try
			//CodeConditionStatement ifelse = new CodeConditionStatement();

			//// add if condition
			//ifelse.Condition = generateIFCodeExpressionWF(bruleSymbol,
			//    out ruleExecutions, out vocabulary, out executeRuleNames,
			//    ref parameters, ref bruleIDs, ref ruleConstIDs);

			// add parameters to method
			foreach ( KeyValuePair<string,string> name_type in parameters ) {
				Type typeParam = Helpers.GetDotNetTypeOfDataTypeString(name_type.Value);
				CodeTypeReference typeRefParam = null;
				if ( typeParam.IsValueType ) {
					typeRefParam = new CodeTypeReference();
					typeRefParam.BaseType = "System.Nullable";
					typeRefParam.TypeArguments.Add(typeParam);
				} else {
					typeRefParam = new CodeTypeReference(typeParam);
				}
				method.Parameters.Add(
					new CodeParameterDeclarationExpression(
						typeRefParam,
						name_type.Key));
			}
			// insert generated ruleExecution statement before the ifelse CodeConditionStatement
			if ( ruleExecutions != null ) {
				foreach ( CodeStatement statement in ruleExecutions ) {
					trycatch.TryStatements.Insert(0, statement);
				}
			}

			// add statements to method
			trycatch.TryStatements.AddRange(statements);

			// add result strings to results-list
			foreach ( THENResultSymbol thenSym in bruleSymbol.ThenList ) {
				if ( !string.IsNullOrEmpty(thenSym.ResultString) &&
					 !results.Contains(thenSym.ResultString) ) {
					results.Add(thenSym.ResultString);
				}
			}
			if ( !string.IsNullOrEmpty(bruleSymbol.Else.ResultString) &&
				 !results.Contains(bruleSymbol.Else.ResultString) ) {
				results.Add(bruleSymbol.Else.ResultString);
			}

			//// add return "THEN-ResultString";
			//ifelse.TrueStatements.Add(
			//    new CodeMethodReturnStatement(
			//        new CodePrimitiveExpression(bruleSymbol.ThenElse.ThenResultString)));
			//results.Add(bruleSymbol.ThenElse.ThenResultString);

			//// add return "ELSE-ResultString";
			//if ( bruleSymbol.ThenElse.ElseResultString.Trim() != "" ) {
			//    ifelse.FalseStatements.Add(
			//    new CodeMethodReturnStatement(
			//        new CodePrimitiveExpression(bruleSymbol.ThenElse.ElseResultString)));
			//    results.Add(bruleSymbol.ThenElse.ElseResultString.Trim());
			//}

			//// add if-else to type statements
			//trycatch.TryStatements.Add(ifelse);

			// add new clause, "trace" and "return null" to catch
			CodeMethodReturnStatement catchReturn = new CodeMethodReturnStatement();	// return ...
			if ( string.IsNullOrEmpty(bruleSymbol.OnError.ResultString) ) {
				catchReturn.Expression = new CodePrimitiveExpression(null);			// null
			} else {
				catchReturn.Expression =
					new CodePrimitiveExpression(bruleSymbol.OnError.ResultString);	// "ONERROR" - ResultString
			}
			trycatch.CatchClauses.Add(
				new CodeCatchClause(									// catch ( Exception ex ) ...
					"ex",
					new CodeTypeReference(typeof(Exception)),
					new CodeExpressionStatement(
						new CodeMethodInvokeExpression(						// Trace.WriteLine( ...
							new CodeTypeReferenceExpression(typeof(Trace)),
							"WriteLine",
							new CodeMethodInvokeExpression(						// ex.ToString() ...
								new CodeVariableReferenceExpression("ex"),
								"ToString"))),								// ... );
					catchReturn												// return ...
				));

			return method;
		}

		private static CodeStatementCollection generateIFCodeExpressionWF(
			BusinessRuleSymbol bruleSymbol,
			out CodeStatementCollection ruleExecutions,
			out List<string> vocabulary,
			out List<string> executeRuleNames,
			ref Dictionary<string, string> parameters,
			ref List<int> ruleIDs,
			ref List<int> ruleConstIDs)
		{
			CodeStatementCollection statements = new CodeStatementCollection();

			ruleExecutions = new CodeStatementCollection();
			vocabulary = new List<string>();
			executeRuleNames = new List<string>();

			if ( bruleSymbol.IfList.Count > 0 ) {
				foreach ( THENResultSymbol thenSym in bruleSymbol.ThenList ) {
					CodeStatementCollection ruleExec;
					List<string> vocab;
					List<string> ruleNames;
					// generate composite if conditions with AND/OR based on connected symbols
					CodeExpression codeExpr = generateIFCodeExpressionRecursiveWF(
						thenSym,
						out ruleExec, out vocab, out ruleNames,
						ref parameters, ref ruleIDs, ref ruleConstIDs);
					if ( codeExpr != null ) {
						if ( ruleExec != null && ruleExec.Count > 0 )
							ruleExecutions.AddRange(ruleExec);
						if ( vocab != null && vocab.Count > 0 )
							vocabulary.AddRange(vocab);
						if ( ruleNames != null && ruleNames.Count > 0 )
							executeRuleNames.AddRange(ruleNames);

						CodeConditionStatement condition = new CodeConditionStatement();
						condition.Condition = codeExpr;
						condition.TrueStatements.Add(
							new CodeMethodReturnStatement(
								new CodePrimitiveExpression(thenSym.ResultString)));
						statements.Add(condition);
					}
				}
			}
			if ( !string.IsNullOrEmpty(bruleSymbol.Else.ResultString) ) {
				statements.Add(
					new CodeMethodReturnStatement(
						new CodePrimitiveExpression(bruleSymbol.Else.ResultString)));
			} else {
				statements.Add(
					new CodeMethodReturnStatement(
						new CodePrimitiveExpression(null)));
			}
			return statements;
		}

		private static CodeExpression generateIFCodeExpressionRecursiveWF(
			DesignerControl current,
			out CodeStatementCollection ruleExecutions,
			out List<string> vocabulary,
			out List<string> executeRuleNames,
			ref Dictionary<string, string> parameters,
			ref List<int> bruleIDs,
			ref List<int> ruleConstIDs)
		{
			RepositoryService repSvc = (RepositoryService)current.GetService(typeof(RepositoryService));
			Debug.Assert(repSvc != null);

			CodeExpression codeExprCurrent = null;
			CodeExpression codeExprLast = null;
			DesignerControl[] aPredecessors = current.GetPredecessors();
			List<DesignerControl> predecessors = new List<DesignerControl>(aPredecessors);
			predecessors.Sort(delegate(DesignerControl x, DesignerControl y)
			{
				IFSymbol ifx = x as IFSymbol;
				IFSymbol ify = y as IFSymbol;
				if ( ifx != null && ify != null ) {
					return ifx.Top - ify.Top;
				} else if ( ifx != null ) {
					return 1;
				} else if ( ify != null ) {
					return -1;
				} else {
					return 0;
				}
			});
			ruleExecutions = new CodeStatementCollection();
			vocabulary = new List<string>();
			executeRuleNames = new List<string>();

			foreach ( DesignerControl dc in predecessors ) {
				CodeStatementCollection currentRuleExec = null;
				List<string> currentVocab = null;
				List<string> currentRules = null;

				// be sure that codeExprCurrent is null
				codeExprCurrent = null;
				if ( dc is Designer.Generic.ANDSymbol || dc is Designer.Generic.ORSymbol ) {
					// generate CodeExpression for current ANDSymbol or ORSymbol
					codeExprCurrent = generateIFCodeExpressionRecursiveWF(dc,
						out currentRuleExec, out currentVocab, out currentRules,
						ref parameters, ref bruleIDs, ref ruleConstIDs);
				} else if ( dc is Designer.BRules.IFSymbol ) {
					// generate the CodeExpress for the current IFSymbol
					codeExprCurrent = generateIFConditionCodeExpressionWF(
						( (Designer.BRules.IFSymbol)dc ).IFCondition,
						out currentRuleExec, out currentVocab, out currentRules,
						ref parameters, ref bruleIDs, ref ruleConstIDs, repSvc);
				}
				if ( currentRuleExec != null ) {
					// add new rule execution statements to ruleExecutions
					ruleExecutions.AddRange(currentRuleExec);
				}
				// if exists add new vocabulary to vocabulary list
				if ( currentVocab != null && currentVocab.Count > 0 )
					vocabulary.AddRange(currentVocab);
				// if exists add new rule names to rule name list
				if ( currentRules != null && currentRules.Count > 0 )
					executeRuleNames.AddRange(currentRules);

				if ( codeExprCurrent != null && codeExprLast != null ) {
					CodeBinaryOperatorExpression binOp = new CodeBinaryOperatorExpression();
					// combine the current and the last CodeExpression
					// based on the type of the current control
					binOp.Left = codeExprLast;
					binOp.Right = codeExprCurrent;
					if ( current is Designer.Generic.ORSymbol )
						binOp.Operator = CodeBinaryOperatorType.BooleanOr;
					else
						binOp.Operator = CodeBinaryOperatorType.BooleanAnd;
					codeExprLast = binOp;
					codeExprCurrent = null;
				} else if ( codeExprCurrent != null && codeExprLast == null ) {
					// if no last CodeExpression exists
					codeExprLast = codeExprCurrent;
					codeExprCurrent = null;
				}
			}
			if ( ruleExecutions.Count == 0 )
				ruleExecutions = null;

			return codeExprLast;
		}

		//private static int _conditionIndex = 0;
		private static CodeExpression generateIFConditionCodeExpressionWF(
			IFSymbol.Condition condition,
			out CodeStatementCollection ruleExecutions,
			out List<string> vocabulary,
			out List<string> executeRuleNames,
			ref Dictionary<string, string> parameters,
			ref List<int> bruleIDs,
			ref List<int> ruleConstIDs,
			RepositoryService repSvc)
		{
			// initialize vocabulary list and list of executed rule names
			vocabulary = new List<string>();
			executeRuleNames = new List<string>();
			ruleExecutions = null;

			// add used vocabulary to list
			if ( condition.LeftPart == IFSymbol.ConditionPartType.Variable)
				vocabulary.Add(condition.LeftValueString);
			if ( condition.RightPart == IFSymbol.ConditionPartType.Variable)
				vocabulary.Add(condition.RightValueString);

			// add used rules to list
			if ( condition.LeftPart == IFSymbol.ConditionPartType.Rule ) {
				executeRuleNames.Add(condition.LeftValueString);
				if ( !bruleIDs.Contains(condition.LeftRuleID) )
					bruleIDs.Add(condition.LeftRuleID);
			}
			if ( condition.RightPart == IFSymbol.ConditionPartType.Rule ) {
				executeRuleNames.Add(condition.RightValueString);
				if ( !bruleIDs.Contains(condition.RightRuleID) )
					bruleIDs.Add(condition.RightRuleID);
			}

			// add used ruleconstant to list
			if ( condition.LeftPart == IFSymbol.ConditionPartType.RuleConstant ) {
				if ( !ruleConstIDs.Contains(condition.LeftRuleConstID) )
					ruleConstIDs.Add(condition.LeftRuleConstID);
			}
			if ( condition.RightPart == IFSymbol.ConditionPartType.RuleConstant ) {
				if ( !ruleConstIDs.Contains(condition.RightRuleConstID) )
					ruleConstIDs.Add(condition.RightRuleConstID);
			}

			if ( ( condition.LeftPart == IFSymbol.ConditionPartType.Variable ||
				   condition.LeftPart == IFSymbol.ConditionPartType.ProcessVariable ) &&
				 !parameters.ContainsKey(condition.LeftValueString) )
				parameters.Add(condition.LeftValueString, condition.LeftDataTypeString);
			if ( ( condition.RightPart == IFSymbol.ConditionPartType.Variable ||
				   condition.RightPart == IFSymbol.ConditionPartType.ProcessVariable ) &&
				 !parameters.ContainsKey(condition.RightValueString) )
				parameters.Add(condition.RightValueString, condition.RightDataTypeString);

			CodeExpression exprLeft = generatePartWF
				(condition.LeftPart, condition.LeftValueString, condition.LeftDataTypeString,
				condition.LeftRuleID, condition.RightPart, ref parameters, ref bruleIDs, repSvc);
			CodeExpression exprRight = generatePartWF
				(condition.RightPart, condition.RightValueString, condition.RightDataTypeString,
				condition.RightRuleID, condition.LeftPart, ref parameters, ref bruleIDs, repSvc);

			if ( exprLeft == null )
				throw new NullReferenceException(
					"Can't create code for the left side of the IF condition (" + condition.LeftValueString + ").");
			if ( exprRight == null )
				throw new NullReferenceException(
					"Can't create code for the right side of the IF condition (" + condition.RightValueString + ").");
			CodeExpression ifcondition = generateConditionWF(
				condition.LeftPart, condition.LeftDataTypeString, exprLeft, condition.Operator, condition.RightPart, condition.RightDataTypeString, exprRight);
			if ( ifcondition == null )
				throw new NullReferenceException(
					"Can't create code for the IF condition (" + condition.ToString() + ").");

			return ifcondition;
		}

		private static CodeMethodInvokeExpression getRuleExecutionWF(
			string ruleName, int ruleID, RepositoryService repSvc,
			ref Dictionary<string, string> parameters,
			ref List<int> bruleIDs)
		{
			if ( ruleID > 0 ) {
				Repository.RepositoryBusinessRule brule = null;
				try {
					brule = repSvc.GetItem<Repository.RepositoryBusinessRule>(ruleID);
				} catch ( Repository.RepositoryItemDeletedException ) {
					brule = null;
				}
				if ( brule == null )
					return null;

				Dictionary<string, string> ruleparams = brule.GetParameters();
				List<int> ruleusedids = brule.GetUsedBusinessRuleIDs();
				List<CodeArgumentReferenceExpression> lstParams = new List<CodeArgumentReferenceExpression>();
				foreach ( KeyValuePair<string, string> ruleparam in ruleparams ) {
					lstParams.Add(new CodeArgumentReferenceExpression(ruleparam.Key));
					parameters[ruleparam.Key] = ruleparam.Value;
				}
				foreach ( int id in ruleusedids ) {
					if ( !bruleIDs.Contains(id) )
						bruleIDs.Add(id);
				}
				return new CodeMethodInvokeExpression(
					//RE: 2008-06-26: if rules are configurable then the methods are not static
					null,//new CodeTypeReferenceExpression("OpenComposite.Orchestration.Rules"),
					ruleName,
					lstParams.ToArray());
				//} else {
				//    return new CodeConditionStatement(
				//        new CodeBinaryOperatorExpression(
				//            new CodeMethodInvokeExpression(null, ruleName),
				//            CodeBinaryOperatorType.IdentityEquality,
				//            new CodePrimitiveExpression(false)),
				//        new CodeMethodReturnStatement(new CodePrimitiveExpression(false)));
			} else {
				return null;
			}
		}
		private static CodeExpression generatePartWF(
			IFSymbol.ConditionPartType conditionPartType,
			string valueString,
			string dataType,
			int bruleID,
			IFSymbol.ConditionPartType otherPartType,
			ref Dictionary<string, string> parameters,
			ref List<int> bruleIDs,
			RepositoryService repSvc)
		{
			CodeExpression codeExpr = null;
			if ( conditionPartType == IFSymbol.ConditionPartType.String ||
				 conditionPartType == IFSymbol.ConditionPartType.ResultString ) {
				if ( otherPartType == IFSymbol.ConditionPartType.Number )
					codeExpr = new CodeMethodInvokeExpression(			// double.Parse("valueString")
						new CodeTypeReferenceExpression(typeof(double)),
						"Parse",
						new CodePrimitiveExpression(valueString));
				else
					codeExpr = new CodePrimitiveExpression(valueString);// "valueString"
			} else if ( conditionPartType == IFSymbol.ConditionPartType.Number ) {
				double d;
				if ( double.TryParse(valueString, out d) )
					codeExpr = new CodePrimitiveExpression(d);			// 100000 => valueString as double
				else
					codeExpr = new CodePrimitiveExpression(valueString);// "valueString"
			} else if ( conditionPartType == IFSymbol.ConditionPartType.Boolean ) {
				BooleanConverter bc = new BooleanConverter();
				try {
					codeExpr = new CodePrimitiveExpression(bc.ConvertFromString(valueString));// True => valueString as bool
				} catch {
					codeExpr = new CodePrimitiveExpression(valueString);// "valueString"
				}
			} else if ( conditionPartType == IFSymbol.ConditionPartType.Variable || 
				        conditionPartType == IFSymbol.ConditionPartType.ProcessVariable ) {
				// generate variable condition part
				codeExpr = new CodeArgumentReferenceExpression(valueString);
			} else if ( conditionPartType == IFSymbol.ConditionPartType.Rule ) {
				codeExpr = getRuleExecutionWF(valueString, bruleID, repSvc, ref parameters, ref bruleIDs);
			} else if ( conditionPartType == IFSymbol.ConditionPartType.RuleConstant ) {
				//object o = Global.Data.ConvertString(valueString, dataType);
				//if ( o != null )
				//    codeExpr = new CodePrimitiveExpression(o);
				//else
				//    codeExpr = new CodePrimitiveExpression(valueString);
				codeExpr = new CodeVariableReferenceExpression(CodeGen.ConstPrefix + valueString);
			}
			return codeExpr;
		}
		private static CodeExpression generateConditionWF(
			IFSymbol.ConditionPartType lefttype, string leftdatatype, CodeExpression left,
			IFSymbol.ConditionOperator op,
			IFSymbol.ConditionPartType righttype, string rightdatatype, CodeExpression right)
		{
			CodeExpression codeExpr;

			switch ( op ) {
				case IFSymbol.ConditionOperator.Equals:
					codeExpr = new CodeBinaryOperatorExpression(	// left == right
						left, CodeBinaryOperatorType.IdentityEquality, right);
					break;
				case IFSymbol.ConditionOperator.NotEquals:
					codeExpr = new CodeBinaryOperatorExpression(	// left != right
						left, CodeBinaryOperatorType.IdentityInequality, right);
					break;
				case IFSymbol.ConditionOperator.Greater:
					codeExpr = new CodeBinaryOperatorExpression(	// left > right
						left, CodeBinaryOperatorType.GreaterThan, right);
					break;
				case IFSymbol.ConditionOperator.Less:
					codeExpr = new CodeBinaryOperatorExpression(	// left < right
						left, CodeBinaryOperatorType.LessThan, right);
					break;
				case IFSymbol.ConditionOperator.GreaterEquals:
					codeExpr = new CodeBinaryOperatorExpression(	// left >= right
						left, CodeBinaryOperatorType.GreaterThanOrEqual, right);
					break;
				case IFSymbol.ConditionOperator.LessEquals:
					codeExpr = new CodeBinaryOperatorExpression(	// left <= right
						left, CodeBinaryOperatorType.LessThanOrEqual, right);
					break;
				case IFSymbol.ConditionOperator.Contains:			// left.Contains(right)
					codeExpr = new CodeMethodInvokeExpression(
						left,
						"Contains",
						right);
					break;
				case IFSymbol.ConditionOperator.NotContains:		// left.Contains(right) == false
					codeExpr = new CodeBinaryOperatorExpression(
						new CodeMethodInvokeExpression(
							left,
							"Contains",
							right),
						CodeBinaryOperatorType.IdentityEquality,
						new CodePrimitiveExpression(false));
					break;
				case IFSymbol.ConditionOperator.HasValue:			// left != null
					if ( Helpers.GetDotNetTypeOfDataTypeString(leftdatatype) == typeof(string) ) {
						//string.IsNullOrEmpty(...) == false
						codeExpr = new CodeBinaryOperatorExpression(
							new CodeMethodInvokeExpression(
								new CodeTypeReferenceExpression(typeof(string)),
								"IsNullOrEmpty",
								left),
							CodeBinaryOperatorType.IdentityEquality,
							new CodePrimitiveExpression(false));
					} else {
						codeExpr = new CodeBinaryOperatorExpression(
							left, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null));
					}
					break;
				case IFSymbol.ConditionOperator.HasNoValue:			// left == null
					if ( Helpers.GetDotNetTypeOfDataTypeString(leftdatatype) == typeof(string) ) {
						//string.IsNullOrEmpty(...)
						codeExpr = new CodeMethodInvokeExpression(
							new CodeTypeReferenceExpression(typeof(string)),
							"IsNullOrEmpty",
							left);
					} else {
						codeExpr = new CodeBinaryOperatorExpression(
							left, CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(null));
					}
					break;
				default:
					codeExpr = null;
					break;
			}

			return codeExpr;
		}
		#endregion

		#endregion

		#endregion
	}
}
